/*
 * @Author: xiaosihan
 * @Date: 2021-03-28 02:13:06
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-03-10 19:25:27
 */

import { Button, Modal, Slider } from "antd";
import { cloneDeep, get, isEmpty, isEqual, pick } from "lodash";
import { Clock, Event, EventDispatcher, MeshStandardMaterial, MeshLambertMaterial, MeshStandardMaterialParameters } from "three";
import queryString from 'query-string';

// 全局公共方法
class Utils extends EventDispatcher {
    constructor() {
        super();
    }

    isProd = import.meta.env.MODE as string === "production";

    isDev = import.meta.env.MODE as string === "development";

    // 获取问号后参数
    getQueryString = (key: string): string => {
        const parsedHash = queryString.parse(location.search);
        return (parsedHash[key] as string) || "";
    }

    // 数字加千分位
    thousand(number: string | number, dot = 0) {
        let strNum = String(Number(Number(number).toFixed(dot))); // 转化成字符串
        while (strNum !== strNum.replace(/(\d)(\d{3})(\.|,|$)/, "$1,$2$3")) {
            strNum = strNum.replace(/(\d)(\d{3})(\.|,|$)/, "$1,$2$3");
        }
        return strNum;
    }

    // 数字转换单位 默认保留2位小数
    numToUnit(num: number, dot = 2) {
        if (Math.abs(num) >= 1000000000000) {
            return { value: this.thousand(num / 1000000000000, dot), unit: "万亿" };
        } else if (Math.abs(num) >= 100000000) {
            return { value: this.thousand(num / 100000000, dot), unit: "亿" };
        } else if (Math.abs(num) >= 10000) {
            return { value: this.thousand(num / 10000, dot), unit: "万" };
        } else {
            return { value: this.thousand(num, dot), unit: "" };
        }
    }

    // 取随机数在某个范围里
    rand(start: number, end: number) {
        return Math.floor(Math.random() * (end - start + 1) + start);
    }

    //随机数组的子元素
    randItem(array: Array<any>) {
        return cloneDeep(array[this.rand(0, array.length - 1)]);
    }

    // 获取是星期几
    getWeekDay() {
        const d = new Date().getDay();
        const arr = ["天", "一", "二", "三", "四", "五", "六"];
        return arr[d];
    }

    // 获取日期
    getDate(seperator: string = ".") {
        // 获取当前日期
        let date = new Date();

        // 获取当前月份
        let nowMonth = date.getMonth() + 1;

        // 获取当前是几号
        let strDate = date.getDate();


        // 对月份进行处理，1-9月在前面添加一个“0”
        if (nowMonth >= 1 && nowMonth <= 9) {
            nowMonth = "0" + nowMonth as any;
        }

        // 对月份进行处理，1-9号在前面添加一个“0”
        if (strDate >= 0 && strDate <= 9) {
            strDate = "0" + strDate as any;
        }

        // 最后拼接字符串，得到一个格式为(yyyy-MM-dd)的日期
        let nowDate = date.getFullYear() + seperator + nowMonth + seperator + strDate;
        return nowDate;
    }

    // 获取时分秒
    getHourMinuteSecond(seperator: string = ":") {
        let today = new Date();
        let h = today.getHours();
        let m = today.getMinutes();
        let s = today.getSeconds();
        // 在 numbers<10 的数字前加上 0
        m = m < 10 ? "0" + m : m as any;
        s = s < 10 ? "0" + s : s as any;
        return h + seperator + m + seperator + s;
    }

    /**
     * 选文件
     */
    async selectFile(accept = ".jpg,.jpeg,.png,.tga", multiple: boolean = false): Promise<File[] | File> {

        return new Promise<File>((resolve, reject) => {
            const input = document.createElement("input");
            input.style.display = "none";
            input.type = "file";
            input.multiple = multiple;
            input.accept = accept;
            input.onchange = (e: any) => {
                const files = e.target.files as PromiseLike<File>;

                if (multiple) {
                    resolve(files);
                } else {
                    resolve((files as unknown as File[])[0]);
                }

            }
            document.body.append(input);
            input.click();
            setTimeout(() => {
                input.remove();
            }, 100);
        });

    }

    /**
     * 选文件转blob
     */
    async selectFileToBlob(accept = ".jpg,.jpeg,.png,.tga", multiple = false): Promise<string[] | string> {
        if (multiple) {
            const files = await this.selectFile(accept, multiple) as File[];
            return files.map(file => window.URL.createObjectURL(file));
        } else {
            const files = await this.selectFile(accept, multiple) as File;
            return window.URL.createObjectURL(files);
        }
    }

    // 选择颜色
    colorPick = (color: `#${string}`, callback: ((this: GlobalEventHandlers, ev: Event) => any) | null) => {
        const input = document.createElement("input");
        input.type = "color";
        input.value = color;
        input.style.position = "absolute";
        input.style.top = "50%";
        input.style.left = "50%";
        input.style.transform = "translate(-50%, -50%)";
        document.body.append(input);
        input.oninput = callback;
        input.onblur = input.remove;
        input.click();
    }

    // 材质编辑
    materialEditor = (name: string, material: MeshStandardMaterial | MeshLambertMaterial) => {

        const params: Partial<MeshStandardMaterialParameters> = {
            name,
            color: material.color.getHexString()
        };

        if (material.transparent) {
            Object.assign(params, { opacity: material.opacity });
        }

        if (material.hasOwnProperty("metalness")) {
            Object.assign(params, { metalness: get(material, ["metalness"]) });
        }

        if (material.hasOwnProperty("roughness")) {
            Object.assign(params, { roughness: get(material, ["roughness"]) });
        }

        Modal.info({
            title: name,
            mask: false,
            content: (() => {

                // 修改参数
                const modifyProp = ({ color, ...parma }: Partial<MeshStandardMaterialParameters>) => {
                    if (color) {
                        Object.assign(params, { color });
                        material.color.set(color);
                    }
                    Object.assign(params, parma);
                    Object.assign(material, parma);
                }

                return (
                    <div>
                        <span>颜色值 </span><input type="color" defaultValue={`#${material.color.getHexString()}`} onChange={e => modifyProp({ color: e.target.value })} /><br />

                        {material.transparent && <>
                            <span>透明度</span> <Slider style={{ width: 250, display: "inline-block", verticalAlign: "middle" }} min={0} max={1} step={0.01} defaultValue={material.opacity} onChange={v => modifyProp({ opacity: v })} />
                        </>}

                        {material.hasOwnProperty("metalness") && <>
                            <span>金属性</span> <Slider style={{ width: 250, display: "inline-block", verticalAlign: "middle" }} min={0} max={1} step={0.01} defaultValue={get(material, ["metalness"])} onChange={v => modifyProp({ metalness: v })} />
                        </>}

                        {material.hasOwnProperty("roughness") && <>
                            <span>粗糙度</span> <Slider style={{ width: 250, display: "inline-block", verticalAlign: "middle" }} min={0} max={1} step={0.01} defaultValue={get(material, ["roughness"])} onChange={v => modifyProp({ roughness: v })} />
                        </>}

                    </div>
                );
            })(),
            okText: "复制参数",
            onOk() {
                navigator.clipboard.writeText(JSON.stringify(params));
            }
        });
    }

    /**
     * 比对指定字段是否相同
     */
    isEqualWidth(obj1: {}, obj2: {}, picks: Array<string> = []) {
        if (isEmpty(picks)) {
            return isEqual(obj1, obj2);
        }
        return isEqual(pick(obj1, picks), pick(obj2, picks));
    }

}

const utils = new Utils();

export default utils;